package com.base.core.tree;

import java.util.*;

public class TreeParser<E extends TreeEntity<E>> {
    //某个节点下所有子节点Id
    private final List<Long> allChildNodeIds = new ArrayList<>();
    //某个节点下所有子节点数据
    private final List<E> allChildNode = new ArrayList<>();
    //某个节点下所有父节点数据
    private final List<E> allParentNode = new ArrayList<>();
    //某个节点下所有父节点Id
    private final List<Long> allParentNodeIds = new ArrayList<>();

    /**
     * 解析树形数据 方法一（递归）
     * @param topId 根元素parentId 一般默认0
     * @param entityList 要转换为树的集合数据节点
     * @return
     * @author biao
     * @date 2020年1月2日
     */
    public List<E> treeList(Long topId, List<E> entityList) {
        List<E> resultList=new ArrayList<>();
        //获取顶层元素集合
        Long parentId;
        for (E entity : entityList) {
            parentId=entity.getParentId();
            if(parentId==null||topId.equals(parentId)){
                resultList.add(entity);
            }
        }
        //获取每个顶层元素的子数据集合
        for (E entity : resultList) {
            entity.setChildList(getSubList(entity.getId(),entityList));
        }
        return resultList;
    }
    /**
     * 获取子数据集合
     * @param id
     * @param entityList
     * @return
     * @author biao
     * @date 2020年1月2日
     */
    private  List<E> getSubList(Long id, List<E> entityList) {
        List<E> childList=new ArrayList<>();
        Long parentId;

        //子集的直接子对象
        for (E entity : entityList) {
            parentId=entity.getParentId();
            if(id.equals(parentId)){
                childList.add(entity);
            }
        }
        //子集的间接子对象
        for (E entity : childList) {
            entity.setChildList(getSubList(entity.getId(), entityList));
        }
        //递归退出条件
        if(childList.size()==0){
            return null;
        }
        return childList;
    }

    /**
     *	 解析树形数据 方法二（非递归）
     *
     * @param entityList
     * @return
     * @author biao
     * @date 2019年3月29日
     */
    public List<E> buildTree(List<E> entityList) {
        List<E> treeList = new ArrayList<>();
        for (E tree : entityList) {
            //找到根
            if (tree.getParentId().equals(0L)) {
                treeList.add(tree);
            }
            //找到子
            for (E treeNode : entityList) {
                if (treeNode.getParentId().equals(tree.getId())) {
                    if(tree.getChildList() == null){
                        tree.setChildList(new ArrayList<>());
                    }
                    tree.getChildList().add(treeNode);
                }
            }
        }
        return treeList;
    }

    /**
     * 解析树形数据 递归方法(三)，功能与上面相同
     *
     * @param list
     * @return
     */
    public List<E> listToTree(List<E> list) {
        //用递归找子。
        List<E> treeList = new ArrayList<>();
        for (E tree : list) {
            if (tree.getParentId().equals(0L)) {
                treeList.add(findChildren(tree, list));
            }
        }
        return treeList;
    }

    /**
     *	 递归查找子节点
     *
     * @param tree
     * @param list
     * @return
     */
    private E findChildren(E tree, List<E> list) {
        for (E node : list) {
            if (node.getParentId().equals(tree.getId())) {
                if(tree.getChildList() == null){
                    tree.setChildList(new ArrayList<>());
                }
                tree.getChildList().add(findChildren(node, list));
            }
        }
        return tree;
    }

    /**
     * 	根据父节点的ID获取所有子节点
     *
     * @param list 分类表
     * @param id   传入的父节点ID
     * @return List<Integer>
     */
    public List<E> findChildNodes(List<E> list, Long id) {
        for (E node : list) {
            //遍历出父id等于参数的id，add进子节点集合
            if (node.getParentId().equals(id)) {
                //递归遍历下一级
                findChildNodes(list, node.getId());
                allChildNode.add(node);
            }
        }
        return allChildNode;
    }

    /**
     * 	根据父节点的ID获取所有子节点id
     *
     * @param list 分类表
     * @param id   传入的父节点ID
     * @return List<Integer>
     */
    public List<Long> findChildNodeIds(List<E> list, Long id) {
        for (E node : list) {
            //遍历出父id等于参数的id，add进子节点集合
            if (node.getParentId().equals(id)) {
                //递归遍历下一级
                findChildNodeIds(list, node.getId());
                allChildNodeIds.add(node.getId());
            }
        }
        return allChildNodeIds;
    }

    /**
     * 根据子节点的ID获取所有父节点
     *
     * @param list 分类表
     * @param id   传入的父节点ID
     * @return List<TreeVo>
     */
    public List<E> findParentNodes(List<E> list, Long id) {
        if (list == null && id == null) {
            return null;
        }
        for (Iterator<E> iterator = list.iterator(); iterator.hasNext(); ) {
            E node = iterator.next();
            // 一、根据传入的某个子节点ID,遍历该子节点的所有父节点
            if (node.getId().equals(id)) {
                findParentNodes(list, node.getParentId());
                allParentNode.add(node);
            }
        }
        return allParentNode;
    }

    /**
     * 根据子节点的ID获取所有父节点
     *
     * @param list 分类表
     * @param id   传入的父节点ID
     * @return List<Integer>
     */
    public List<Long> findParentIds(List<E> list, Long id) {
        if (list == null && id == null) {
            return null;
        }
        for (Iterator<E> iterator = list.iterator(); iterator.hasNext(); ) {
            E node = iterator.next();
            // 一、根据传入的某个子节点ID,遍历该子节点的所有父节点
            if (node.getId().equals(id)) {
                findParentIds(list,node.getParentId());
                allParentNodeIds.add(node.getId());
            }
        }
        return allParentNodeIds;
    }

    public List<E> queryParentTree(List<E> treeList) {
        List<E> parentTreeList = new ArrayList<>();
        List<E> childrenTreeList = new ArrayList<>();
        Map<Long, Long> parentIdMap = new HashMap<Long, Long>();
        if (treeList == null || treeList.size() == 0) {
            return childrenTreeList;
        }
        for (E tree : treeList) {
            parentIdMap.put(tree.getParentId(), tree.getParentId());
        }
        //遍历找出所有的根节点和非根节点
        for (E tree : treeList) {
            if ((tree.getParentId().equals(0L)) || parentIdMap.containsKey(tree.getId())) {
                parentTreeList.add(tree);
            } else {
                childrenTreeList.add(tree);
            }
        }
        //递归获取所有父节点
        if (childrenTreeList != null && childrenTreeList.size() > 0) {
            for (E tree : childrenTreeList) {
                //添加所有父级
                List<E> parents = getParentTreeList(parentTreeList, tree.getParentId());
                tree.setParentList(parents);
            }
        }
        return childrenTreeList;
    }

    //递归查询父节点
    private List<E> getParentTreeList(List<E> parents, Long id) {
        List<E> parentTreeList = new ArrayList<>();
        List<E> childrenTreeList = new ArrayList<>();
        if (parents == null || parents.size() == 0) {
            return childrenTreeList;
        }
        //找出所有的根节点和非根节点
        for (E tree : parents) {
            if (id.equals(tree.getId())) {
                childrenTreeList.add(tree);
            } else {
                parentTreeList.add(tree);
            }
        }
        //查询父节点
        if (childrenTreeList != null && childrenTreeList.size() > 0) {
            for (E tree : childrenTreeList) {
                //递归查询父节点
                List<E> parentList = getParentTreeList(parentTreeList, tree.getParentId());
                tree.setParentList(parentList);
            }
        }
        return childrenTreeList;
    }

    /**
     * 格式化list为树形list 标记叶子类字段
     * @param categoryList
     * @param flag true 表示全部展开，其他 表示不展开
     * @return
     */
    public List<E> formatTree(List<E> categoryList, Boolean flag) {
        List<E> categoryArray = new ArrayList<>();
        for(E node1 : categoryList){
            boolean mark = false;
            for(E node2 : categoryList){
                if(node1.getParentId()!=null && node1.getParentId().equals(node2.getId())){
                    node2.setLeaf(false);
                    mark = true;
                    if(node2.getChildList() == null) {
                        node2.setChildList(new ArrayList<>());
                    }
                    node2.getChildList().add(node1);
                    node2.setExpanded(flag);
                    break;
                }
            }
            if(!mark){
                categoryArray.add(node1);
                node1.setExpanded(flag);
            }
        }
        return categoryArray;
    }


}
